const fs = require('fs');
const OSS = require('ali-oss');
const axios = require('./axios');
const fileUtils = require('@colpu/core/src/utils/file');

/**
 * @class AliOss
 */
module.exports = class AliOSS {
  constructor(options = {}) {
    const DEFAULT = {
      customFolder: '' // 自定义目录，默认在根目录
    };
    this.options = Object.assign({}, DEFAULT, options);

    const ossConfig = this.options;
    if (!ossConfig && (!ossConfig.accessKeyId || !ossConfig.accessKeySecret || !ossConfig.bucket)) {
      throw Error('请传入oss配置参数');
    }
    this.client = new OSS(ossConfig);
  }

  /**
   * @function batchPutStream 批量上传文件到oss
   * @param {Array} files
   * [{
   *  path: 要上传的文件路径,
   *  filename: 要上传的文件名称，如果需要区分目录格式用/分割开，如: filedir/filename
   * }]
   * @param {String} replacePath 要剔除的路径，便于在oss上存储
   * @param {String} prefixRoot 需要在域名前添加的前缀
   */
  batchPutStream(files, replacePath = '', prefixRoot = '') {
    const batchArr = [];
    if (replacePath && replacePath.lastIndexOf('/') > -1) {
      replacePath += '/';
    }

    files.forEach(item => {
      let filename = item.filename;
      if (replacePath) {
        filename = item.path.replace(replacePath, '');
      }

      let saveTo = `${this.options.customFolder}/${prefixRoot}${filename}`;
      batchArr.push(this.putStream(item.path, saveTo));
    });

    return Promise.all(batchArr);
  }

  /**
   * @function putStream
   * @param {String} filepath
   * @param {String} filename
   */
  putStream(filepath, filename) {
    let result;
    try {
      const stream = fs.createReadStream(filepath);
      let contentLength = fs.statSync(filepath).size;
      return this.client.putStream(filename, stream, {
        contentLength
      });
    } catch (err) {
      console.error(err);
      throw new Error(err);
    }
  }

  /**
   * @function putBuffer 上传 buffer 内容
   * @param name  oss 对象(bucket)相对目录地址
   * @param buffer
   * @returns {Promise<T>}
   */
  putBuffer(name, buffer) {
    if (!name || !buffer) {
      throw new Error('upload param error!');
    }
    if (buffer instanceof Buffer) {
      return this.client.put(name, buffer);
    }
  }

  /**
   * 直接上传字符串
   * @param name  oss 对象(bucket)相对目录地址
   * @param str
   * @returns {*}
   */
  putString(name, str) {
    return this.putBuffer(name, Buffer.from(str));
  }

  /**
   * 删除文件对象
   * @param name 文件对象名称 eg. 'ismanhua_prev/static/style/index.css'
   * @returns {Promise<any>}
   */
  async deleteObj(name) {
    try {
      let result = await this.client.delete(name);
      return result;
    } catch (err) {
      console.error(err);
      throw new Error(err);
    }
  }

  /**
   * 获取远程地址url 路径
   * @param relativePath 文档相对路径
   * @returns {string}
   */
  getRemotePath(relativePath) {
    let opt = this.options;
    let domain = opt.oss.accessDomain;
    let folder = opt.oss.customFolder;
    return `${domain}/${folder}${relativePath}`;
  }

  /**
   * 获取远程域名目录地址
   * @returns {string}
   */
  getDomain() {
    let opt = this.options;
    let domain = opt.oss.accessDomain;
    let folder = opt.oss.customFolder;
    return `${domain}/${folder}`;
  }


  /**
   * 下载内容到指定文件
   * @param osObj
   * @param pathname
   */
  downFileTo(osObj, pathname) {
    return axios.get(osObj.url).then(res => {
      if (res.status === 200) {
        if (!fileUtils.existsSync(pathname)) {
          fileUtils.mkdirsSync(pathname);
        }
        fs.writeFile(pathname, res.data, {
          encoding: 'utf-8'
        }, function (err) {
          if (err) {
            console.error(err);
          }
        });
      }
    }).catch(e => {
      console.error(e);
    });
  }

  // 判断文件是否存在
  getFile(filename) {
    const options = this.client.options;
    return this.client.get(filename).then(res => {
      if (res.res.status === 200) {
        // 将Buffer文件转换成字符串
        res.res.content = (res.res.data && res.res.data.toString()) || '';
        return res.res;
      } else {
        return false;
      }
    }).catch(err => {
      // code NoSuchKey表示找不到文件
      if (err.code === 'NoSuchKey') {
        return false;
      }
      console.info(`OSS GET ERROR::${options.accessDomain}/${filename} , ${err.message}`);
    });
  }

  getStream(filename) {
    return this.client.getStream(filename);
  }

  downFile(osObj) {
    return axios.get(osObj.url).then(res => {
      if (res.status === 200) {
        return Object.assign({}, osObj, res);
      } else {
        return null;
      }
    }).catch(e => {
      console.error(e);
      return e;
    });
  }

  /**
   * @function dirList 返回服务目录下所有文件列表
   * @param options
   * @returns {Promise<Array>}
   */
  async dirList(options) {
    let prefix, opt = {};
    if (typeof options === 'string') {
      prefix = options;
    } else {
      prefix = options.prefix;
      opt = options;
    }
    let result = await this.client.list(Object.assign({
      prefix,
      delimiter: '/',
      'max-keys': 1000
    }, opt));
    let objArr = [];
    if (result.objects) {
      objArr = objArr.concat(result.objects);
    }
    if (result.prefixes) {
      for (let i = 0; i < result.prefixes.length; i++) {
        let subPrefix = result.prefixes[i];
        let subObjs = await this.dirList(Object.assign({}, opt, {
          prefix: subPrefix
        }));
        objArr = objArr.concat(subObjs);
      }
    }

    const {
      accessDomain
    } = this.client.options;

    // 纠正下载url，使用自定义域名方式
    objArr.forEach(item => {
      item.url = accessDomain + '/' + item.name;
    });
    return objArr;
  }
};
